package com.nineclock.sign.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.service.SignService;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignPCListDTO;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.feign.OrganizationFeign;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

@SuppressWarnings("all")
@Service
@Slf4j
public class SignServiceImpl implements SignService {

    @Autowired
    private SignInfoMapper signInfoMapper;

    @Autowired
    OrganizationFeign OrganizationFeign;

    /**
     * 当前企业内所有员工 指定时间范围内的签到情况
     * 1. 获取当前企业内所有员工
     * 2. 获取日期区间内 所有的日期
     * 3. 再根据员工 查询 日期区间内每一天的签到情况
     *
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public PageResult<SignPCListDTO> queryMembers(Integer page, Integer pageSize, String startTime, String endTime) {

        //健壮性判断
        if (page == null || pageSize == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        List<SignPCListDTO> signPCListDTOS = new ArrayList<>();

        // 获取日期区间内时间列表
        List<Date> dateList = DateTimeUtil.getDatesBetweenTwoDate(startTime, endTime, "yyyy-MM-dd");

        //把日期列表 转换为 日期字符串列表
        List<String> dateStrList = dateList.stream().map(date -> {
            return DateTimeUtil.dateToStr(date, "yyyy-MM-dd");
        }).collect(Collectors.toList());


        //获取当前企业内所有员工
        PageResult<SysCompanyUserDTO> pageResult = OrganizationFeign.SelectCompanyUser(page, pageSize).getData();
        List<SysCompanyUserDTO> sysCompanyUserDTOS = pageResult.getRows();


        //把员工表 复制为 签到列表
        // List<SignPCListDTO> signPCListDTOList = BeanHelper.copyWithCollection(sysCompanyUserDTOS, SignPCListDTO.class);

        for (SysCompanyUserDTO sysCompanyUserDTO : sysCompanyUserDTOS) {
            SignPCListDTO signInfoDTO = new SignPCListDTO();

            signInfoDTO.setUsername(sysCompanyUserDTO.getUserName());
            signInfoDTO.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
            signInfoDTO.setPost(sysCompanyUserDTO.getPost());
            SysDepartmentDTO sysDepartmentDTO = new SysDepartmentDTO();
            sysDepartmentDTO.setId(sysCompanyUserDTO.getDepartmentId());
            sysDepartmentDTO.setName(sysCompanyUserDTO.getDepartmentName());
            signInfoDTO.setDepartment(sysDepartmentDTO);

            LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
            wrapper.eq(SignInfo::getCompanyUserId, sysCompanyUserDTO.getId());
            wrapper.between(SignInfo::getCreateDate, startTime, endTime);

            List<SignInfo> signInfoList = signInfoMapper.selectList(wrapper);


            //对 签到记录按日期分组
            Map<String, List<SignInfo>> listMap = signInfoList.stream()
                    .collect(Collectors.groupingBy(SignInfo::getCreateDate));

            //存储员工每天的签到情况
            List<SignInfoDTO> signInfoDTOList = new ArrayList<>();


            //循环日期列表
            for (String dateStr : dateStrList) {
                SignInfoDTO signInfoDTO1 = new SignInfoDTO();
                List<SignInfo> infos = listMap.get(dateStr);
                if (infos==null) {
                    signInfoDTO1.setSignCount(0);
                } else {
                    signInfoDTO1.setSignCount(infos.size());
                    signInfoDTO1.setSignDate(dateStr);
                }
                //添加到集合中
                signInfoDTOList.add(signInfoDTO1);
            }


            signInfoDTO.setSigns(signInfoDTOList);
            signPCListDTOS.add(signInfoDTO);
        }


        //要在页面展示的记录

        PageResult<SignPCListDTO> result = new PageResult<>();
        result.setTotalPage(pageResult.getTotalPage());
        result.setTotal(pageResult.getTotal());
        result.setRows(signPCListDTOS);

        return result;
    }

    @Override
    public void exportSign(String startTime, String endTime) throws IOException {

        //获取时间段内签到情况
        List<SignPCListDTO> rows = this.queryMembers(1, 1000, startTime, endTime).getRows();


        //获取相应对象 ，并设置相应对象
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletResponse response = servletRequestAttributes.getResponse();
        response.setHeader("Content-disposition","attachment;filename=Attendance.xlsx");
        response.setContentType("application/json;charset=UTF-8");
        response.setCharacterEncoding("utf-8");


        // *************easyExcel **********

        WriteCellStyle cellStyle = new WriteCellStyle();
        //表头和内容都是水平居中
        cellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("宋体");
        font.setFontHeightInPoints((short)12);
        cellStyle.setWriteFont(font);

        HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(cellStyle,cellStyle);

        EasyExcel.write(response.getOutputStream())
                .head(handlerHead(rows))
                .registerWriteHandler(styleStrategy)
                .registerWriteHandler(new MyColumnStyle())
                .sheet("测试数据")
                .doWrite(handlerData(rows));

        // *************easyExcel **********

    }

    /**
     * 操作数据
     * @return
     */
    private List<List<String>> handlerData(List<SignPCListDTO> signPCListDTOS) {
        List<List<String>> data = new ArrayList<>();

        //循环每一个员工
        for (SignPCListDTO signPCListDTO : signPCListDTOS) {
            List<String> list = new ArrayList<>();
            list.add(signPCListDTO.getUsername());
            list.add(signPCListDTO.getWorkNumber());
            list.add(signPCListDTO.getDepartment().getName());
            list.add(signPCListDTO.getPost());

            //取出员工每天的签到状态
            List<SignInfoDTO> signInfoDTOList = signPCListDTO.getSigns();
                for (SignInfoDTO signInfoDTO : signInfoDTOList) {
                    list.add(signInfoDTO.getSignCount()+"");
            }

            data.add(list);
        }
        return data;
    }

    /**
     * 操作表头
     * @return
     */
    private List<List<String>> handlerHead(List<SignPCListDTO> signPCListDTOS) {
        List<List<String>> head = new ArrayList<>();
        head.add(Arrays.asList("姓名"));
        head.add(Arrays.asList("工号"));
        head.add(Arrays.asList("部门"));
        head.add(Arrays.asList("职位"));
        //获取集合中的第一个对象
        //获取第一个员工每天签到情况 对应日期
        SignPCListDTO signPCListDTO = signPCListDTOS.get(0);
        List<SignInfoDTO> signs = signPCListDTO.getSigns();
        for (SignInfoDTO sign : signs) {
            head.add(Arrays.asList(sign.getSignDate()));
        }



        return head;
    }

    class MyColumnStyle extends AbstractColumnWidthStyleStrategy {

        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder,
                                      List<CellData> cellDataList,
                                      Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
            writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 4500);
        }
    }
}


